#ifndef _MATCHER_
#define _MATCHER_

#include"util.hpp"
#include"online_user.hpp"
#include"user_table.hpp"
#include"room.hpp"

template<class T>
class Match_Queue
{
public:
    // 获取队列长度
    int size()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.size();
    }

    // 判断队列是否为空
    bool empty()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.empty();
    }

    // 线程等待
    void wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }

    // 用户加入匹配
    void push(const T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.push_back(data);
        // 唤醒条件变量
        _cond.notify_all();
    }

    // 用户匹配成功
    bool pop(T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if(_list.empty())
        {
            return false;
        }

        data=_list.front();
        _list.pop_front();
        return true;
    }

    // 用户退出匹配
    void remove(T &data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.remove(data);
    }
private:
    std::list<T> _list;
    std::mutex _mutex;
    std::condition_variable _cond;      //条件变量
};

class Matcher
{
public:
    Matcher(Room_Manager* rm,User_Table* ut,Online_Manager* om)
    :_rm(rm),_ut(ut),_om(om),
    _th_low(std::thread(&Matcher::th_low_entry,this)),
    _th_mid(std::thread(&Matcher::th_mid_entry,this)),
    _th_high(std::thread(&Matcher::th_high_entry,this))
    {
        INF_LOG("Match_Queue init");
    }

    // 添加用户
    bool add(uint64_t uid)
    {
        Json::Value user;
        bool ret=_ut->select_by_id(uid,user);
        if(ret==false)
        {
            ERR_LOG("get user info failed");
            return false;
        }
        int score=user["score"].asInt();

        if(score<1500)
        {
            _q_low.push(uid);
        }
        else if(score<2000&&score>=1500)
        {
            _q_mid.push(uid);
        }
        else
        {
            _q_high.push(uid);
        }
        return true;
    } 

    // 删除用户
    bool del(uint64_t uid)
    {
        Json::Value user;
        bool ret=_ut->select_by_id(uid,user);
        if(ret==false)
        {
            ERR_LOG("get user info failed");
            return false;
        }
        int score=user["score"].asInt();

        if(score<1500)
        {
            _q_low.remove(uid);
        }
        else if(score<2000&&score>=1500)
        {
            _q_mid.remove(uid);
        }
        else
        {
            _q_high.remove(uid);
        }
        return true;
    }

private:
    // 匹配处理函数
    void handle_match(Match_Queue<uint64_t> &mq)
    {
        while(1)
        {
            // 如果匹配队列小于2人，线程等待
            while(mq.size()<2)
            {
                mq.wait();
            }

            // 匹配成功，用户出队列
            uint64_t uid1,uid2;
            bool ret=mq.pop(uid1);
            if(ret==false)
            {
                continue;
            }
            ret=mq.pop(uid2);
            if(ret==false)
            {
                continue;
            }

            // 判断用户连接状态
            wsserver_t::connection_ptr conn1,conn2;
            _om->get_conn_game_hall(uid1,conn1);
            if(conn1.get()==nullptr)
            {
                this->add(uid2);
                continue;
            }
            _om->get_conn_game_hall(uid2,conn2);
            if(conn2.get()==nullptr)
            {
                this->add(uid1);
                continue;
            }

            room_ptr rp=_rm->create_room(uid1,uid2);
            if(rp.get()==nullptr)
            {
                this->add(uid1);
                this->add(uid2);
                continue;
            }

            // 返回匹配成功信息
            Json::Value resp;
            resp["optype"]="match_success";
            resp["result"]=true;
            resp["reason"]="匹配成功";
            std::string body;
            Json_Util::serialize(resp,body);
            conn1->send(body);
            conn2->send(body);
        }
    }

    void th_low_entry()
    {
        return handle_match(_q_low);
    }

    void th_mid_entry()
    {
        return handle_match(_q_mid);
    }

    void th_high_entry()
    {
        return handle_match(_q_high);
    }
private:
    Match_Queue<uint64_t> _q_low;       //分数<1500
    Match_Queue<uint64_t> _q_mid;       //分数>=1500且<2000
    Match_Queue<uint64_t> _q_high;      //分数>=2000

    std::thread _th_low;
    std::thread _th_mid;
    std::thread _th_high;

    Room_Manager* _rm;
    User_Table* _ut;
    Online_Manager* _om;
};

#endif